#include "HelperSingleNumber.h"

Operations HelperSingleNumber::getActions(IPuzzle *pz,int nStep)  //获取一个解题操作集合（参数为期望数）
{
    Operations ops;
    int n=0;
    //思考：如何判定不同情况下的唯一数的难度系数？（在候选数模式下，显式的简单；非候选数模式下，隐式的可能会更简单点）

    //唯一数，在某一个CellSet里，该候选数只出现了一次（隐）
    //在某一个数格里只有一个候选数也是唯一数（显式）

	//搜索显式唯一数
	//搜索隐式唯一数
    vector<ICellSets> csslist ;
    set<ICell *> sncells; //记录已经添加的数格，避免重复添加

    csslist.push_back(pz->getCellSets(CellSet_Y));
    csslist.push_back(pz->getCellSets(CellSet_X));
    csslist.push_back(pz->getCellSets(CellSet_Z));

    for(unsigned int i=0;i<csslist.size();++i) //对所有的数格集合进行遍历（隐式唯一数必须要遍历每个限制条件）
    {
        ICellSets css=csslist[i];
        for(unsigned int j=0;j<csslist[i].size();++j)
        {
            ICellSet *cs=css[j]; /*取得某一行列宫*/
            ICells cells=cs->getCells();
            vector<int> cnt(UPPER_BOUNDER); //已经初始化０
            ICells tmpcells(UPPER_BOUNDER); //记录候选数对应的数格

            //用来收集CellSet里的显式唯一数
            map<Number,ICell *> nakeCells;

            //统计候选数出现次数
            for(unsigned int k=0;k<cells.size();++k)
            {
                ICell *c=cells[k];
                if(c->getNumber()>0) continue ;//跳过对已经设置的数字的处理
                ICandidates cands=c->getCandidates();
                bool isNaked=true;
                Number numSingle=UPPER_BOUNDER+1;
                //cout << "CheckCell "<< c->toString()<<endl;
                for(int m=0;m<UPPER_BOUNDER;++m)
                {
                    ICandidate *cand=cands[m];
                    if(cand->getValue()==STA_NORMAL)
                    {
                        //cout << (m+1) << " is STA_NORMAL. ("<<numSingle<<")"<<endl;
                        if(numSingle==UPPER_BOUNDER+1)
                            numSingle=m+1;
                        else
                            isNaked=false;
                        if(cnt[m]++<1)
                            tmpcells[m]=c;
                    }
                    //else cout << (m+1) << " is not STA_NORMAL. ("<<numSingle<<")"<<endl;
                }
                if(isNaked)
                {
                    //cout << "Number "<<numSingle<< " is Naked Single Number!"<<endl;
                    nakeCells[numSingle]=c;
                }
            }

            if(nakeCells.size()>0)
            {
                //有显式唯一数
                for(map<Number,ICell *>::iterator itor=nakeCells.begin();itor!=nakeCells.end();++itor)
                {
                    if(sncells.find(itor->second)!=sncells.end()) continue; //已经收集了该数格，不用重复添加了
                    Operation op(OperationSetNumber,nID); //设置技巧ＩＤ，参见 ID_HELPER_ENUM 枚举类型
                    op.addNumber(itor->first);
                    op.addPoint(itor->second->getPoint());
                    sncells.insert(itor->second);
                    char tmp[200];
                    sprintf(tmp,"在%s发现%s有显式唯一数%d",cs->toString(),itor->second->getPoint().toString(),itor->first);
                    //cout<<tmp<<endl;
                    op.setDesc(tmp);
                    ops.push_back(op);
                    if(++n >= nStep)
                        return ops;
                }
            }

            //校验累积和
            for(int m=0;m<UPPER_BOUNDER;++m)
            {
                if(cnt[m]==1 ) //发现隐式唯一数
                {
//                    if(nakeCells.find(m+1)!=nakeCells.end())
//                    {
//                        //此隐式唯一数已经作为显式唯一数记录，跳过
//                        continue;
//                    }
                    if(sncells.find(tmpcells[m])!=sncells.end()) continue; //已经收集了该数格，不用重复添加了
                    Operation op(OperationSetNumber,nID); //设置技巧ＩＤ，参见 ID_HELPER_ENUM 枚举类型
                    op.addNumber(Number(m+1));
                    op.addPoint(tmpcells[m]->getPoint());
                    sncells.insert(tmpcells[m]);
                    char tmp[200];
                    sprintf(tmp,"在%s发现%s有隐式唯一数%d",cs->toString(),tmpcells[m]->getPoint().toString(),m+1);
                    //cout<<tmp<<endl;
                    op.setDesc(tmp);
                    ops.push_back(op);
                    if(++n >= nStep)
                        return ops;
                    //可能会发现多个隐式唯一数！所以注释下一行
                    //else break;
                }
            }
        }
    }
    return ops;
}
